#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <string.h>
#include <dirent.h>
#include "do_server.h"

static void gen_header (int fd, int status, char *msg, size_t len, char *type)
{
	char buff[2048], tmpline[512];

	sprintf(buff, "HTTP/1.1 %d %s\r\n", status, msg);
	sprintf(tmpline, "Content-Length: %d\r\n", len);
	strcat(buff, tmpline);
	sprintf(tmpline, "Conten-Type: %s\r\n\r\n", type);
	strcat(buff, tmpline);

	if (write(fd, buff, strlen(buff)) < 0) {
		perror("gen header write");
		exit(-1);
	}
}

static void gen_404(int fd)
{
	char buff[2048], tmpline[512], html[1024];

	sprintf(html, "%s", "<html><head><title>Not Found</title></head>"
				 "<body><strong>Not Found</strong></body>");

	sprintf(tmpline, "HTTP/1.1 404 Not Found\r\n");
	strcpy(buff, tmpline);
	
	sprintf(tmpline, "Content-Length: %d\r\n", strlen(html));
	strcat(buff, tmpline);

	sprintf(tmpline, "Content-type: text/html\r\n\r\n");
	strcat(buff, tmpline);

	strcat(buff, html);

	if (write(fd, buff, sizeof(buff)) < 0) {
		perror("write");
	}
}

void list_dir(int fd, DIR *dir)
{
	char tmpline[1024], html[4096];
	struct dirent *dt;

	bzero(html, sizeof(html));
	strcpy(html, "<html><head><title>DIR List</title></head><body>");
	while ((dt = readdir(dir)) != NULL) {
		sprintf(tmpline, "<a href=\"%s\">%s</a><br/>", dt->d_name, dt->d_name);
		strcat(html, tmpline);
	}
	strcat(html, "</body></html>");

	gen_header(fd, 200, "OK", strlen(html), "text/html");
	if (write(fd, html, sizeof(html)) < 0) {
		perror("list dir");
		exit(EXIT_FAILURE);
	}
}

void do_post (TinyBuff *tb, Url *url)
{

}

void do_get (TinyBuff *tb, Url *url)
{
	struct stat st;
	DIR *dir;
	int ret, ofd;
	char *addr;

#ifdef DEBUG
	printf("filename %s\n", url->uri);
#endif
	/* url->uri is a directory*/
	if ((dir = opendir(url->uri)) != NULL) {
		list_dir(tb->fd, dir);
	} else if (stat(url->uri, &st) == -1) {
		printf("%d: %s\n", errno, strerror(errno));
		switch (errno) {
			case ENOENT: /* file not exist*/
				gen_404(tb->fd);
			case EACCES:
				gen_404(tb->fd);
			default: 
				break;
		}
	} else {
		gen_header(tb->fd, 200, "OK", st.st_size, "text/html");
		if ((ofd = open(url->uri, O_RDONLY)) == -1) {
			perror("open");
			exit(-1);
		}
		if ((addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, ofd, 0)) == MAP_FAILED) {
			perror("mmap");
			exit(-1);
		}
		if (write(tb->fd, addr, st.st_size) < 0) {
			perror("write");
			exit(-1);
		}
	}
}
